home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / 2m30src.zip / 2M-INDOC.C < prev    next >
C/C++ Source or Header  |  1995-03-06  |  29KB  |  862 lines

  1.  
  2. /*───────────────────────────────────────────────────────────────────\
  3. │                                                                    │
  4. │         Lector del fichero de documentación para 2M-INFO.          │
  5. │                                                                    │
  6. │         El programa utiliza sólo español o inglés para los         │
  7. │         mensajes propios, pero el fichero de documentación         │
  8. │         soportaría varios idiomas más.                             │
  9. │                                                                    │
  10. │                (C) 1994-1995 Ciriaco García de Celis               │
  11. │                                                                    │
  12. \───────────────────────────────────────────────────────────────────*/
  13.  
  14. #include <conio.h>
  15. #include <stdio.h>
  16. #include <alloc.h>
  17. #include <string.h>
  18. #include <io.h>
  19. #include <dos.h>
  20. #include "2m-info.h"
  21.  
  22.  
  23. #define  MAX_IDIOMAS  10  /* número máximo de idiomas soportado */
  24. #define  MAX_MENUS    21  /* número máximo de submenús + principal */
  25. #define  MAX_TITULO   60  /* longitud máxima de los títulos de menús */
  26. #define  MAX_PAISES   24  /* nº máximo códigos telefónicos soportados */
  27. #define  MAX_NPAIS    15  /* tamaño máximo del nombre del país */
  28.  
  29. #define  OP_SALIR     -1
  30. #define  OP_ALTX      -2
  31. #define  OP_765DEBUG  -3
  32. #define  OP_FDTR      -4
  33. #define  OP_IDIOMA    -5
  34.  
  35. #define  CV    15  /* color para miniventanas */
  36. #define  CFV    1  /* color de fondo para miniventanas */
  37. #define  CM    15  /* color para los menús */
  38. #define  CLM   11  /* color para la línea de los menús */
  39. #define  CF9   14  /* color para F9 */
  40. #define  CFM    1  /* color de fondo para los menús */
  41. #define  CFMS   3  /* color para la sombra de los menús */
  42. #define  CC    15  /* color durante carga de datos */
  43. #define  CFC    4  /* color de fondo durante carga de datos */
  44. #define  CI    15  /* color de impresión para el texto */
  45. #define  CFI    1  /* color de fondo de impresión para el texto */
  46. #define  CG    14  /* color de impresión de gráficos y cuadros */
  47. #define  CE    14  /* color para las líneas de estado */
  48. #define  CFE    2  /* color de fondo para las líneas de estado */
  49.  
  50.  
  51. typedef struct {
  52.   int  numitems;                         /* número de líneas del menú */
  53.   char titulo[MAX_MENUS][MAX_TITULO];    /* mensaje a imprimir */
  54.   char *texto[MAX_MENUS];                /* punteros a textos en memoria */
  55.   long offseek[MAX_MENUS];               /* offset a textos en fichero */
  56.   int  numlineas[MAX_MENUS];             /* nº líneas en fichero */
  57.   } Menu;
  58.  
  59. typedef struct {
  60.   char  nombre[MAX_NPAIS+1]; /* nombre del idioma */
  61.   short pais[MAX_PAISES];    /* códigos telefónicos de países que lo hablan */
  62.   } Idioma;
  63.  
  64.  
  65. extern   int  set80x30 (void);
  66. extern   int  Tecla (void);
  67. extern   int  EsOS2 (void);
  68. extern   int  EsWinEnh (void);
  69. extern   int  semilla;
  70. extern   int  sp;
  71. extern   void debug765 (void);
  72. extern   void ResetVideo (void);
  73. extern   void fdtr (int, int);
  74. extern   void CursorOff (void);
  75. extern   void BrilloOn (void);
  76. extern   void ventana (int, int, int, int, int, int, int);
  77. extern   void v3dg (int, int, int, int, int, int, int, int, int);
  78. extern   void v3df (int, int, int, int, int, int, int, int);
  79. extern   void boton (int, int, int, int, int, int, char *);
  80. extern   void Estrellas (void);
  81. extern   unsigned rnd (unsigned);
  82.  
  83.  
  84. FILE     *AbrirFDA (char *, char *);
  85. int      MemoriaInsuficiente (void),
  86.          CrearMenus (FILE *, char *, char *, Menu *[][MAX_MENUS], Idioma *, int *),
  87.          ConstruirIDX (FILE *, char *, char *, Menu *[][MAX_MENUS], Idioma *, int *),
  88.          parseint (char **),
  89.          EligeIdioma (Idioma *, int),
  90.          PintarMenu (int, Menu *, char *, int *),
  91.          justificar (unsigned char **, unsigned char *);
  92. void     LiberarMemoria (Menu *[][MAX_MENUS], int, int),
  93.          ImprimirTexto (Menu *[][MAX_MENUS], int, int, int, int, FILE *),
  94.          Estrellas (void),
  95.          Visualizar (char *, char *),
  96.          clreof (int, int, unsigned *, int),
  97.          display (unsigned char **, unsigned *, unsigned, unsigned);
  98. char     *parsestr (char *);
  99.  
  100. char     far *LineasPant = MK_FP (0x40, 0x84);
  101.  
  102.  
  103. int VerFicheroDoc (char *dir, char *fich, char *fichindice, Parametros *cmd)
  104. {
  105.   FILE   *fichdoc;      /* handle para el fichero de documentación */
  106.   int    nm,            /* número de menus en cada idioma */
  107.          ni,            /* número de idiomas */
  108.          idioma,        /* idioma en uso */
  109.          opcion,
  110.          subopc,
  111.          accion, subacc,
  112.          modo30;
  113.   long   sm;
  114.   char   *idstr;
  115.   Menu   *menu[MAX_IDIOMAS][MAX_MENUS];
  116.   Idioma idiom[MAX_IDIOMAS];
  117.  
  118.   if (MemoriaInsuficiente()) return (0);
  119.  
  120.   if ((fichdoc=AbrirFDA(dir, fich))==NULL) return (1);
  121.  
  122.   for (ni=0; ni<MAX_IDIOMAS; ni++)
  123.     for (nm=0; nm < MAX_MENUS; nm++) menu[ni][nm]=NULL;  /* menús a 0 */
  124.  
  125.   if (!cmd->HazIdx)
  126.     nm = CrearMenus (fichdoc, dir, fichindice, menu, idiom, &ni);
  127.   if (cmd->HazIdx || !nm)
  128.     nm = ConstruirIDX (fichdoc, dir, fichindice, menu, idiom, &ni);
  129.  
  130.   idioma = EligeIdioma (idiom, ni); if (cmd->ModoI) idioma = (ni-1)-idioma;
  131.  
  132.   modo30=1;
  133.   if (((EsOS2() || (EsWinEnh() && (EsWinEnh() < 0x400))) &&
  134.     (!cmd->Modo30)) || (cmd->Modo25)) modo30=0;
  135.  
  136.   if (modo30)
  137.       set80x30();
  138.     else
  139.       *LineasPant=24;  /* asegurar variable BIOS inicializada */
  140.  
  141.   Estrellas();
  142.  
  143.   opcion = subopc = 0;
  144.   do {
  145.     sp = (strstr(idiom[idioma].nombre, "ESPAÑOL")!=NULL);
  146.     idstr = idiom[idioma!=ni-1? idioma+1: 0].nombre;
  147.     accion=PintarMenu (0, menu[idioma][0], idstr, &opcion);
  148.     switch (accion) {
  149.       case OP_SALIR:
  150.       case OP_ALTX:     break;
  151.       case OP_765DEBUG: ResetVideo(); debug765();
  152.                         if (modo30) set80x30(); Estrellas();
  153.                         break;
  154.       case OP_FDTR:     ResetVideo(); fdtr (0, 0);
  155.                         if (modo30) set80x30(); Estrellas();
  156.                         break;
  157.       case OP_IDIOMA:   idioma++; if (idioma>=ni) idioma=0; break;
  158.       default:
  159.         sm = - (menu[idioma][0]->offseek[opcion]);
  160.         if (sm > 0) do {
  161.               sp = (strstr(idiom[idioma].nombre, "ESPAÑOL")!=NULL);
  162.               idstr = idiom[idioma!=ni-1? idioma+1: 0].nombre;
  163.               subacc = PintarMenu (1, menu[idioma][sm], idstr, &subopc);
  164.               switch (subacc) {
  165.                 case OP_SALIR:
  166.                 case OP_ALTX:     break;
  167.                 case OP_765DEBUG: ResetVideo(); debug765();
  168.                                   if (modo30) set80x30(); Estrellas();
  169.                                   break;
  170.                 case OP_FDTR:     ResetVideo(); fdtr (0, 0);
  171.                                   if (modo30) set80x30(); Estrellas();
  172.                                   break;
  173.                 case OP_IDIOMA:   idioma++; if (idioma>=ni) idioma=0; break;
  174.                 default: ImprimirTexto (menu, idioma, ni, sm, subopc, fichdoc);
  175.                                   Estrellas();
  176.                                   break;
  177.                 }
  178.             } while ((subacc != OP_SALIR) && (subacc != OP_ALTX));
  179.           else
  180.             ImprimirTexto (menu, idioma, ni, 0, opcion, fichdoc); Estrellas();
  181.         break;
  182.       }
  183.   } while ((accion != OP_SALIR) && (accion != OP_ALTX));
  184.  
  185.   fclose (fichdoc);
  186.   if (nm) LiberarMemoria (menu, ni, nm);
  187.  
  188.   return (accion == OP_ALTX);
  189. }
  190.  
  191.  
  192. FILE *AbrirFDA (char *directorio, char *fichero)
  193. {
  194.   char nfich[64];
  195.   FILE *f;
  196.  
  197.   strcpy (nfich, directorio); strcat (nfich, fichero);
  198.   if ((f=fopen(nfich, "rt"))==NULL) {
  199.     ventana (ABRIR, 21, 10, 59, 16, CV, CFV);
  200.     if (sp) {
  201.         gotoxy (3,2); cputs ("Fichero "); cputs(fichero);
  202.                       cputs(" no encontrado");
  203.         gotoxy (12,4); cputs("Pulse una tecla");
  204.         }
  205.       else {
  206.         gotoxy (6,2); cputs ("File "); cputs(fichero);
  207.                       cputs(" not found");
  208.         gotoxy (13,4); cputs("Press any key");
  209.         }
  210.     CursorOff(); Tecla();
  211.     ventana (CERRAR, 21, 10, 59, 16, 0, 0);
  212.     }
  213.  
  214.   return (f);
  215. }
  216.  
  217.  
  218. int MemoriaInsuficiente()  /* Asegurar un mínimo de memoria */
  219. {
  220.   char *bloque;
  221.   int  insuficiente=1;
  222.  
  223.   if ((bloque=farmalloc(5120L))==NULL) {
  224.       ventana (ABRIR, 21, 10, 59, 16, CV, CFV);
  225.       if (sp) {
  226.           gotoxy (10,2); cputs ("Memoria insuficiente");
  227.           gotoxy (12,4); cputs("Pulse una tecla");
  228.           }
  229.         else {
  230.           gotoxy (10,2); cputs ("Insufficient memory");
  231.           gotoxy (13,4); cputs("Press any key");
  232.           }
  233.       CursorOff(); Tecla();
  234.       ventana (CERRAR, 21, 10, 59, 16, 0, 0);
  235.       }
  236.     else {
  237.       insuficiente=0;
  238.       farfree (bloque);
  239.       }
  240.  
  241.   return (insuficiente);
  242. }
  243.  
  244.  
  245. int CrearMenus (FILE *fdoc, char *dir, char *fichidx,
  246.                 Menu *menus[][MAX_MENUS], Idioma *idiom, int *NumIdiomas)
  247. {
  248.   char   nfich[64];
  249.   int    NumMenus, i, j, iniv;
  250.   long   tamanio;
  251.   struct ftime ff, fechahora;
  252.   FILE   *fidx;
  253.  
  254.   iniv = (*LineasPant - 4) >> 1;
  255.  
  256.   NumMenus=0;
  257.   ventana (ABRIR, 24, iniv, 56, iniv+4, CV, CFV);
  258.   gotoxy (12,2); if (sp) cputs("Espere..."); else cputs(" Wait...");
  259.   CursorOff();
  260.  
  261.   strcpy (nfich, dir); strcat (nfich, fichidx);
  262.   if ((fidx=fopen(nfich, "r+b"))!=NULL) {
  263.     fseek (fidx, 96L, SEEK_SET);
  264.     fread (&tamanio, sizeof(long), 1, fidx);
  265.     fread (&fechahora, sizeof (fechahora), 1, fidx);
  266.     getftime (fileno(fdoc), &ff);
  267.     if ((memcmp(&ff, &fechahora, sizeof (ff))==0) &&
  268.        (tamanio==filelength(fileno(fdoc)))) {
  269.       fread (NumIdiomas, sizeof(int), 1, fidx);
  270.       fread (&NumMenus, sizeof(int), 1, fidx);
  271.       fseek (fidx, 128L, SEEK_SET);
  272.       for (i=0; i < *NumIdiomas; i++) {
  273.         for (j=0; j < NumMenus; j++) {
  274.           menus [i][j] = farmalloc (sizeof(Menu));
  275.           fread (menus[i][j], sizeof(Menu), 1, fidx);
  276.           }
  277.         fread (&idiom[i], sizeof(Idioma), 1, fidx);
  278.         }
  279.       }
  280.     fclose (fidx);
  281.     }
  282.  
  283.   ventana (CERRAR, 24, iniv, 56, iniv+4, 0, 0);
  284.  
  285.   return (NumMenus);
  286. }
  287.  
  288.  
  289. int ConstruirIDX (FILE *doc, char *directorio, char *fichidx,
  290.                   Menu *menus[][MAX_MENUS], Idioma *idiom, int *NumIdiomas)
  291. {
  292.   char   bf[96], *p;
  293.   int    i, j, idioma, lineas=0, nm, itemm, items;
  294.   long   tamanio;
  295.   struct ftime fechahora;
  296.   FILE   *fidx;
  297.  
  298.   ventana (ABRIR, 12, 10, 67, 17, CV, CFV);
  299.   if (sp) {
  300.       gotoxy (4,2); cputs ("El fichero de índice rápido ("); cputs (fichidx); cputs(")  no se");
  301.       gotoxy (4,3); cputs ("corresponde con el de documentación o no existe.");
  302.       gotoxy (4,4); cputs ("Se está creando nuevamente.  Esta  tarea  podría");
  303.       gotoxy (4,5); cputs ("llevar varios segundos.");
  304.       }
  305.     else {
  306.       gotoxy (4,2); cputs ("Fast access  index  file  ("); cputs (fichidx); cputs(")  is  not");
  307.       gotoxy (4,3); cputs ("relationed with documentation file or not exist.");
  308.       gotoxy (4,4); cputs ("It is being created again.  This  work may takes");
  309.       gotoxy (4,5); cputs ("some seconds.");
  310.       }
  311.   CursorOff();
  312.  
  313.   for (i=0; i<MAX_IDIOMAS; i++) {
  314.     for (j=0; j<MAX_MENUS; j++) menus[i][j]=NULL;
  315.     memset (&idiom[i], 0, sizeof (Idioma));
  316.     }
  317.  
  318.   idioma=0;
  319.   while (!feof (doc)) {
  320.     if (fgets (bf, 80, doc)==NULL) break;
  321.     lineas++;
  322.     if ((p=strstr(bf, "{INICIOIDIOMA"))!=NULL) {
  323.       nm = 1;
  324.       itemm = items = -1;
  325.       p+=13; i=0; while (*p == ' ') p++;
  326.       while ((*p != ':') && (i<MAX_NPAIS))
  327.         idiom [idioma].nombre[i] = *p++, i++;
  328.       idiom [idioma].nombre[i] = 0; p++; i=0;
  329.       do {
  330.         j = parseint (&p);
  331.         if (j==-2) {
  332.             fgets (bf, 80, doc); p = bf;
  333.             j = parseint (&p);
  334.             }
  335.           else
  336.             idiom [idioma].pais[i++] = j;
  337.         } while ((j>0) && (i<MAX_PAISES));
  338.       lineas=0;
  339.       }
  340.     else if ((p=strstr(bf, "{FINIDIOMA")) != NULL) {
  341.       if (items != -1) {  /* cerrar submenú */
  342.         menus[idioma][nm]->numlineas[items] = lineas-1;
  343.         menus[idioma][nm]->numitems = items+1;
  344.         nm++;
  345.         items = -1;
  346.         }
  347.       if (itemm>0) menus[idioma][0]->numlineas[itemm] = lineas;
  348.       menus[idioma][0]->numitems = itemm+1;
  349.       idioma++;
  350.       }
  351.     else if ((p=strstr(bf, "{LINEAMENU")) != NULL) {
  352.       if (items != -1) {  /* cerrar submenú */
  353.         menus[idioma][nm]->numlineas[items] = lineas-1;
  354.         menus[idioma][nm]->numitems = items+1;
  355.         nm++;
  356.         items = -1;
  357.         }
  358.       if (itemm>=0) menus[idioma][0]->numlineas[itemm] = lineas-1;
  359.         else {
  360.           menus[idioma][0] = farmalloc (sizeof(Menu));
  361.           memset (menus[idioma][0], 0, sizeof(Menu));
  362.           }
  363.       itemm++; lineas=0;
  364.       strncpy (menus[idioma][0]->titulo[itemm], parsestr (p+10), MAX_TITULO);
  365.       menus[idioma][0]->offseek[itemm] = ftell(doc);
  366.       menus[idioma][0]->texto[itemm] = NULL;
  367.       }
  368.     else if ((p=strstr(bf, "{LINEASUBMENU")) != NULL) {
  369.       if (items>=0) menus[idioma][nm]->numlineas[items] = lineas-1;
  370.         else {
  371.           menus[idioma][nm] = farmalloc (sizeof(Menu));
  372.           memset (menus[idioma][nm], 0, sizeof(Menu));
  373.           menus[idioma][0]->offseek[itemm] = -nm;  /* menú -> submenú */
  374.           }
  375.       items++; lineas=0;
  376.       strncpy (menus[idioma][nm]->titulo[items], parsestr (p+13), MAX_TITULO);
  377.       menus[idioma][nm]->offseek[items] = ftell(doc);
  378.       menus[idioma][nm]->texto[items] = NULL;
  379.       }
  380.     }
  381.  
  382.   *NumIdiomas = idioma;
  383.  
  384.   strcpy (bf, directorio); strcat (bf, fichidx);
  385.   remove (bf);
  386.   if ((fidx=fopen(bf, "w+b"))!=NULL) {
  387.       for (i=0; i<96; i++) bf[i]=0;
  388.       strcpy (bf, "\r\nFichero índice para acceso rápido.\r\nFast access index file.\r\n\032");
  389.       fwrite (bf, 96, 1, fidx);
  390.       tamanio=filelength(fileno(doc));
  391.       getftime (fileno(doc), &fechahora);
  392.       fwrite (&tamanio, sizeof(long), 1, fidx);
  393.       fwrite (&fechahora, sizeof(fechahora), 1, fidx);
  394.       fwrite (NumIdiomas, sizeof(int), 1, fidx);
  395.       fwrite (&nm, sizeof(int), 1, fidx);
  396.       for (i=0; i<32; i++) bf[i]=0; fwrite (bf, 32, 1, fidx);
  397.       fseek (fidx, 128L, SEEK_SET);
  398.       for (i=0; i < *NumIdiomas; i++) {
  399.         for (j=0; j < nm; j++)
  400.           fwrite (menus[i][j], sizeof(Menu), 1, fidx);
  401.         fwrite (&idiom[i], sizeof(Idioma), 1, fidx);
  402.         }
  403.       fclose (fidx);
  404.       }
  405.  
  406.   ventana (CERRAR, 12, 10, 67, 17, 0, 0);
  407.   return (nm);
  408. }
  409.  
  410.  
  411. void LiberarMemoria (Menu *menus[][MAX_MENUS], int ni, int nm)
  412. {
  413.   int i, j, k;
  414.  
  415.   for (i=0; i<ni; i++)
  416.     for (j=0; j<nm; j++) {
  417.       for (k=0; k < menus[i][j]->numitems; k++)
  418.         if (menus[i][j]->texto[k] != NULL) farfree (menus[i][j]->texto[k]);
  419.       farfree (menus[i][j]);
  420.       }
  421. }
  422.  
  423.  
  424. int parseint (char **p)
  425. {
  426.   int num=0;
  427.  
  428.   if (**p == '}') return (-1);
  429.   if (**p == '\n') return (-2);
  430.  
  431.   do {
  432.     while (**p == ' ') (*p)++;
  433.     if ((**p >= '0') && (**p <= '9')) {
  434.       num *= 10;
  435.       num += **p -'0';
  436.       }
  437.     if (**p == '*') num=-3;
  438.     (*p)++;
  439.   } while ((**p != ',') && (**p != '}'));
  440.  
  441.   if (**p != '}') (*p)++;
  442.  
  443.   return (num);
  444. }
  445.  
  446.  
  447. char *parsestr (char *p)
  448. {
  449.   char *pp;
  450.  
  451.   while ((*p == ' ') || (*p == '[')) p++;
  452.   pp=p; while ((*p != ']') && (*p != '}')) p++; *p=0;
  453.   return (pp);
  454. }
  455.  
  456.  
  457. int EligeIdioma (Idioma *idiom, int ni)
  458. {
  459.   union REGS r; struct SREGS s;
  460.   char  info[64];
  461.   int   idioma, i, j;
  462.  
  463.   idioma=0;
  464.   for (i=0; i<ni; i++) if (idiom[i].pais[0] == -3) idioma=i; /* por defecto */
  465.  
  466.   if (_osmajor>=3) {
  467.     r.x.ax=0x3800; s.ds=FP_SEG(info); r.x.dx=FP_OFF(info);
  468.     intdosx (&r, &r, &s);
  469.     for (i=0; i<ni; i++)
  470.       for (j=0; idiom[i].pais[j] > 0; j++)
  471.         if (idiom[i].pais[j] == r.x.bx) idioma = i;
  472.     }
  473.  
  474.   return (idioma);
  475. }
  476.  
  477.  
  478. int PintarMenu (int nivel, Menu *menu, char *idinombre, int *opc)
  479. {
  480.   int         lx, ly, cx, cy, i, tecla, cod=0, salir=0;
  481.   static char *buffer[2];
  482.  
  483.   ly = menu->numitems + 3;
  484.   lx = 0;
  485.   for (i=0; i < menu->numitems; i++)
  486.     if (strlen (menu->titulo[i]) > lx) lx = strlen(menu->titulo[i]);
  487.   lx += 5;
  488.  
  489.   cx = (80-lx) >> 1; cy = ((*LineasPant + 1) - ly) >> 1;
  490.   if (cy+ly >= 25) cy = 24-ly;   /* no usar 5 últimas líneas en 80x30 */
  491.  
  492.   if ((buffer[nivel]=farmalloc (2L*(lx+3)*(ly+2)))!=NULL)
  493.     gettext (cx, cy, cx+lx+2, cy+ly+1, buffer[nivel]);
  494.  
  495.   window (cx+2, cy+1, cx+lx+2, cy+ly+1); textbackground (CFMS); clrscr();
  496.   window (cx, cy, cx+lx, cy+ly); textbackground (CFM); clrscr();
  497.   textcolor (CLM); putch ('┌');
  498.   for (i=2; i<=ly; i++) {
  499.     gotoxy (1, i); putch('│');
  500.     gotoxy (lx+1, i); putch('│');
  501.     }
  502.   for (i=2; i<=lx; i++) {
  503.     gotoxy (i, 1); putch('─');
  504.     gotoxy (i, ly+1); putch('─');
  505.     }
  506.   gotoxy (lx+1, 1); putch('┐'); gotoxy (1, ly+1); putch('└');
  507.   cod=_wscroll; _wscroll=0; gotoxy (lx+1, ly+1); putch('┘'); _wscroll=cod;
  508.   window (cx+1, cy+1, cx+lx-1, cy+ly-1);
  509.  
  510.   do {
  511.     textcolor (CM); textbackground (CFM);
  512.     for (i=0; i < menu->numitems; i++) {
  513.       gotoxy (2, i+2); putch(' '); cputs (menu->titulo[i]); putch(' '); }
  514.     gotoxy (lx - strlen (idinombre) - 4, i+2);
  515.     textcolor (CF9); cputs ("F9 "); cputs(idinombre);
  516.  
  517.     if (peekb(0x40, 0x49) != 7) {
  518.         textcolor (CFM); textbackground (CM); }
  519.       else {
  520.         textcolor (0); textbackground (7); }
  521.     gotoxy (2, *opc+2); putch(' '); cputs (menu->titulo[*opc]); putch(' ');
  522.  
  523.     CursorOff();
  524.     tecla = Tecla();
  525.     switch (tecla) {
  526.       case 0x4300:  /* F9 */        cod=OP_IDIOMA; salir=1;  break;
  527.       case ' ':
  528.       case '2':
  529.       case 0x5000:  /* cur ab  */   (*opc)++;                break;
  530.       case '8':
  531.       case 0x4800:  /* cur arr */   (*opc)--;                break;
  532.       case '7':
  533.       case 0x4700:  /* Home */
  534.       case '9':
  535.       case 0x4900:  /* PgUp */      *opc=0;                  break;
  536.       case 27:      /* ESC */       if (nivel==1) { salir=1; break; }
  537.                                     if (*opc == menu->numitems-1)
  538.                                       salir=1;
  539.       case '1':
  540.       case 0x4F00:  /* End */
  541.       case '3':
  542.       case 0x5100:  /* PgDn */      *opc = menu->numitems-1; break;
  543.       }
  544.     if (*opc<0) *opc = menu->numitems-1;
  545.     if (*opc >= menu->numitems) *opc=0;
  546.   } while ((tecla != 13) && (tecla != 0x2D00) && (!salir));
  547.  
  548.   if (cod != OP_IDIOMA) {
  549.     cod = *opc;
  550.     if (tecla == 0x2D00)                               cod = OP_ALTX;
  551.     else if ((*opc == menu->numitems-1) || (salir))    cod = OP_SALIR;
  552.     else if (strstr (menu->titulo[*opc], "765DEBUG"))  cod = OP_765DEBUG;
  553.     else if (strstr (menu->titulo[*opc], "FDTR"))      cod = OP_FDTR;
  554.     }
  555.  
  556.   if (buffer[nivel] != NULL) {
  557.     puttext (cx, cy, cx+lx+2, cy+ly+1, buffer[nivel]);
  558.     farfree (buffer[nivel]); buffer[nivel]=NULL;
  559.     }
  560.  
  561.   window (1,1,80,25);
  562.  
  563.   return (cod);
  564. }
  565.  
  566.  
  567. void ImprimirTexto (menu, idioma, ni, submenu, opcion, fichdoc)
  568. Menu *menu[][MAX_MENUS];
  569. int  idioma, ni, submenu, opcion;
  570. FILE *fichdoc;
  571. {
  572.   long tbuffer;   /* longitud total del texto */
  573.   int  idi,       /* idioma en curso para liberar memoria */
  574.        id,        /* contador de idiomas para liberar memoria */
  575.        sb,        /* submenú en curso para liberar memoria */
  576.        sl,        /* opción del submenú en curso para liberar memoria */
  577.        ex,        /* variable de control de huida del bucle */
  578.        cargar,    /* indica si hay que traer los datos de disco */
  579.        li, iniv;
  580.   char *p, *k;
  581.  
  582.   tbuffer = 81L * menu[idioma][submenu]->numlineas[opcion] + 1;
  583.   idi = idioma - 1; if (idi<0) idi = ni-1;
  584.  
  585.   cargar = menu[idioma][submenu]->texto[opcion] == NULL;
  586.  
  587.   iniv = (*LineasPant - 4) >> 1;
  588.  
  589.   if (cargar) {
  590.     ventana (ABRIR, 34, iniv, 46, iniv+4, CC, CFC);
  591.     gotoxy (2,2); if (sp) cputs ("Espere..."); else cputs(" Wait...");
  592.     CursorOff();
  593.     }
  594.  
  595.   ex=1; /* pedir memoria; si hace falta, liberando alguna opción */
  596.   while ((menu[idioma][submenu]->texto[opcion] == NULL) && ex)
  597.     if ((menu[idioma][submenu]->texto[opcion]=farmalloc (tbuffer))==NULL)
  598.       for (ex = id = 0; (id < ni) && !ex; id++, idi = (idi+ni-1) % ni)
  599.         for (sb=0; (menu[idi][sb]!=NULL) && !ex; sb++)
  600.           for (sl=0; (sl < menu[idi][sb]->numitems) && !ex; sl++)
  601.             if (menu[idi][sb]->texto[sl] != NULL) {
  602.               farfree (menu[idi][sb]->texto[sl]);
  603.               menu[idi][sb]->texto[sl] = NULL;
  604.               ex++;
  605.               }
  606.  
  607.   if (menu[idioma][submenu]->texto[opcion] == NULL) {
  608.        ventana (CERRAR, 34, iniv, 46, iniv+4, 0, 0);
  609.        ventana (ABRIR, 28, iniv, 51, iniv+4, CV, CFV);
  610.        gotoxy (2,2);
  611.        cputs(sp? "Memoria Insuficiente": "Insufficient memory");
  612.        CursorOff(); delay(1500); while (kbhit()) (void) getch();
  613.        ventana (CERRAR, 28, iniv, 51, iniv+4, 0, 0);
  614.        }
  615.      else {
  616.       if (cargar) {
  617.           fseek (fichdoc, menu[idioma][submenu]->offseek[opcion], SEEK_SET);
  618.           p = menu[idioma][submenu]->texto[opcion];
  619.           for (li=0; li < menu[idioma][submenu]->numlineas[opcion]; li++) {
  620.             fgets (p, 80, fichdoc);
  621.             if (strlen(p)>1) {
  622.                 k = p;  p += strlen(p);  *(p-1) = 10;
  623.                 while ((*(p-2)==' ') && (p-k > 1)) { p--; *(p-1)=10; }
  624.                 }
  625.               else
  626.                 *p++=' ', *p++=10;
  627.             }
  628.           p--; *(p-1) = 0;
  629.           farrealloc (menu[idioma][submenu]->texto[opcion],
  630.                       p - menu[idioma][submenu]->texto[opcion]+1);
  631.           }
  632.  
  633.       if (cargar) ventana (CERRAR, 34, iniv, 46, iniv+4, 0, 0);
  634.  
  635.       Visualizar (menu[idioma][submenu]->titulo[opcion],
  636.                   menu[idioma][submenu]->texto[opcion]);
  637.       }
  638. }
  639.  
  640.  
  641. void Visualizar (char *titulo, char *cadena)
  642. {
  643.   unsigned char *vram, *p, *ap, status[80];
  644.   unsigned      *bram;
  645.   unsigned      lineas, linea, ln, cars, atrp, atrg, atrs, off, tecla, i;
  646.  
  647.   CursorOff();
  648.  
  649.   lineas = *LineasPant + 1;
  650.  
  651.   vram = MK_FP ((peekb(0x40, 0x49) & 0x7F) == 7 ? 0xB000:0xB800, 0);
  652.  
  653.   if (peekb(0x40, 0x49) != 7) {
  654.       atrp = ((CFI << 4) | CI) << 8;  atrs = ((CFE << 4) | CE) << 8;
  655.       atrg = ((CFI << 4) | CG) << 8;
  656.       }
  657.     else {
  658.       atrp = 15 << 8;  atrs = 7 << 12;  /* mono */
  659.       atrg =  7 << 8;
  660.       }
  661.  
  662.   bram = (unsigned *) vram;
  663.   cars = 80;
  664.   while (cars--) *bram++=atrs | ' ';
  665.   bram = (unsigned *) vram + (lineas-1)*80;
  666.   cars = 80;
  667.   while (cars--) *bram++=atrs | ' ';
  668.  
  669.   bram = (unsigned *) vram;
  670.  
  671.   off = (80 - strlen(titulo)) >> 1;
  672.   p = titulo; while (*p) bram [off++] = atrs | *p++;   /* título */
  673.  
  674.   strcpy (status, sp?
  675.   "              Teclas:  \030  \031  RePág  AvPág  Inicio  Fin  Intro-Salir":
  676.   "                 Keys:  \030  \031  PgUp  PgDn  Home  End  Enter-Exits");
  677.   off = (lineas-1)*80;
  678.   p = status; while (*p) bram [off++] = atrs | *p++;   /* status */
  679.  
  680.   p = cadena;
  681.   for (linea = 1; (linea <= lineas-2) && *p; linea++)
  682.     display (&p, &bram[linea*80], atrp, atrg);
  683.  
  684.   clreof (linea, lineas, bram, atrp);
  685.  
  686.   do {
  687.     tecla = Tecla();
  688.     switch (tecla) {
  689.       case ' ':
  690.       case '2':
  691.       case 0x5000: /* cur ab  */
  692.                    ap = p; ln = linea;
  693.                    while (linea < lineas-1) {
  694.                      while ((*p != 10) && *p) p++;
  695.                      if (*p) p++; linea++;
  696.                      }
  697.                    if (*p) {
  698.                        memmove (&bram[80], &bram[160], (lineas-3)*160);
  699.                        display (&p, &bram[(linea-1)*80], atrp, atrg);
  700.                        }
  701.                      else {
  702.                        p=ap; linea=ln;
  703.                        }
  704.                    break;
  705.       case '8':
  706.       case 0x4800: /* cur arr */
  707.                    linea++;
  708.                    while ((linea>0) && (p-cadena)) {
  709.                      while ((*p != 10) && (p!=cadena)) p--; linea--;
  710.                      if (p-cadena) p--; }
  711.                    if (linea<2) {
  712.                        p++; if (!linea) p++;
  713.                        linea=2;
  714.                        memmove (&bram[160], &bram[80], (lineas-3)*160);
  715.                        display (&p, &bram[(linea-1)*80], atrp, atrg);
  716.                        }
  717.                      else linea=1;
  718.                    break;
  719.       case '9':
  720.       case 0x4900: /* PgUp */
  721.                    for (i=0; (i < lineas+linea-2) && (p-cadena); i++) {
  722.                      while ((*p != 10) && (p-cadena)) p--;
  723.                      p--;
  724.                      }
  725.                    if (p-cadena) p+=2;
  726.                    for (linea = 1; (linea <= lineas-2) && *p; linea++)
  727.                      display (&p, &bram[linea*80], atrp, atrg);
  728.                    clreof (linea, lineas, bram, atrp);
  729.                    break;
  730.       case '3':
  731.       case 0x5100: /* PgDn */
  732.                    for (i=0; (i < lineas-1-linea) && (*p); i++) {
  733.                      while ((*p != 10) && (*p)) p++;
  734.                      p++;
  735.                      }
  736.                    for (linea = 1; (linea <= lineas-2) && *p; linea++)
  737.                      display (&p, &bram[linea*80], atrp, atrg);
  738.                    if (linea>1) {
  739.                      clreof (linea, lineas, bram, atrp);
  740.                      break;
  741.                      }
  742.       case '1':
  743.       case 0x4F00: /* End */
  744.                    while (*p++);
  745.                    linea=lineas;
  746.                    while ((linea>0) && (p-cadena)) {
  747.                      while ((*p != 10) && (p!=cadena)) p--; linea--;
  748.                      if (p-cadena) p--; }
  749.                    if (p-cadena) p+=2;
  750.                    for (linea = 1; (linea <= lineas-2) && *p; linea++)
  751.                      display (&p, &bram[linea*80], atrp, atrg);
  752.                    clreof (linea, lineas, bram, atrp);
  753.                    break;
  754.       case '7':
  755.       case 0x4700: /* Home */
  756.                    p = cadena;
  757.                    for (linea = 1; (linea <= lineas-2) && *p; linea++)
  758.                      display (&p, &bram[linea*80], atrp, atrg);
  759.                    clreof (linea, lineas, bram, atrp);
  760.                    break;
  761.       }
  762.   } while ((tecla != 27) && (tecla != 13) && (tecla != 0x2D00));
  763. }
  764.  
  765.  
  766. void clreof (int linea, int lineas, unsigned *bram, int fondo)
  767. {
  768.   int i;
  769.   unsigned char *p, pp[81];
  770.  
  771.   for (i=0; i<79; i++) pp[i]=' '; pp[i]=10;
  772.  
  773.   for (i=linea; i<=lineas-2; i++) {
  774.     p=pp;
  775.     display (&p, &bram[i*80], fondo, fondo);
  776.     }
  777. }
  778.  
  779.  
  780. void display (unsigned char **texto, unsigned *pant, unsigned c1, unsigned c2)
  781. {
  782.   int      off=0, relleno, color;
  783.   unsigned char justificado[80], *p;
  784.  
  785.   relleno = (color = justificar (texto, justificado) ? c2 : c1) | ' ';
  786.  
  787.   p = justificado;
  788.  
  789.   pant [off++] = relleno; while (*p) pant [off++] = *p++ | color;
  790.  
  791.   while (off<80) pant [off++] = relleno;  /* clreol */
  792.  
  793.   (*texto)++;
  794. }
  795.  
  796.  
  797. int justificar (unsigned char **texto, unsigned char *j)
  798. {
  799.   unsigned char *p, c0, c1;
  800.   int      justif=1, i, ii, lon, izq=0, tipo, grafico=0;
  801.   char     ais[6][3]={". ",
  802.                       ", ",  /* casos preferidos para insertar espacios */
  803.                       "; ",
  804.                       ": ",
  805.                       ") ",
  806.                       " ("};
  807.  
  808.   p = *texto; while (*p == ' ') { p++; izq++; }
  809.  
  810.   while ((*p != 10) && *p && justif) {
  811.     switch (*p) {
  812.       case 218:  /* '┌' */   /* ('┌' es signed y da problemas) */
  813.       case 179:  /* '│' */
  814.       case 195:  /* '├' */
  815.       case 192:  /* '└' */
  816.       case 196:  /* '─' */
  817.       case 219:  /* '█' */
  818.       case 220:  /* '▄' */
  819.       case 223:  /* '▀' */ grafico++;
  820.                            justif=0;  break;  /* sin justificar */
  821.       case 240:  /* '≡' */ justif=0;  break;
  822.       }
  823.     p++;
  824.     }
  825.  
  826.   if (justif) {
  827.     p = *texto;
  828.     while ((*p != 10) && *p) p++;
  829.     if (*p && (*(p+2)==10) || (*(p+2)==0)) justif=0;
  830.     }
  831.  
  832.   p = j;
  833.   while ((**texto != 10) && **texto)
  834.     if (**texto != 240) {
  835.         *p++=**texto; (*texto)++;
  836.         }
  837.       else
  838.         (*texto)++;  /* saltar '≡' */
  839.   *p=0;
  840.  
  841.   lon=strlen(j);
  842.  
  843.   if (justif && (lon > 64) && (izq<5))
  844.     while (lon < 78) {
  845.       for (tipo=0; (tipo<6) && (lon<78); tipo++)
  846.         for (i = lon-1; (i > izq) && (lon < 78); i--)
  847.           if ((j[i] == ais[tipo][1]) && (j[i-1] == ais[tipo][0])) {
  848.             c0 = ' ';
  849.             for (ii=i; j[ii-1] ;ii++) { c1=j[ii]; j[ii]=c0; c0=c1; }
  850.             lon++;
  851.             }
  852.       for (i = lon-1; (i > izq) && (lon < 78); i--)
  853.         if ((j[i]==' ') && (j[i-1] != ' ')) {
  854.           c0 = ' ';
  855.           for (ii=i; j[ii-1] ;ii++) { c1=j[ii]; j[ii]=c0; c0=c1; }
  856.           lon++;
  857.           }
  858.     }
  859.  
  860.   return (grafico);
  861. }
  862.